/**
 * @ Author: luoqi
 * @ Create Time: 2024-07-12 09:27
 * @ Modified by: luoqi
 * @ Modified time: 2025-03-25 19:53
 * @ Description:
 */
#include <stdarg.h>
#include <stdbool.h>
#include "bsp.h"
#include "printf.h"

static TX_EVENT_FLAGS_GROUP _events_communicate;

#define _UART1_TX_EVENT (1 << 0)
#define _UART1_RX_EVENT (1 << 1)
#define _USB_RX_EVENT   (1 << 2)
#define _USB_TX_EVENT   (1 << 3)

static bool _osstartup = false;

static RingBuffer _rb_uart1_rx;
static uint8_t _rb_uart1_rx_buf[64];
static uint8_t _uart1_rx_buf[64];

static RingBuffer _rb_uart1_tx;
static uint8_t _rb_uart1_tx_buf[2048];
static TX_THREAD _task_uart1_send;
static uint8_t _task_uart1_send_stack[512];
static void _task_uart1_send_hdl(uint32_t args);
static TX_SEMAPHORE _sem_uart1_tx;
static TX_MUTEX _mutex_rb_uart1_tx;

static RingBuffer _rb_usb_recv;
static uint8_t _rb_usb_recv_buf[2048];

static TX_THREAD _task_usb_send;
static uint8_t _task_usb_send_stack[2048];
static TX_MUTEX _mutex_usb_send;
static RingBuffer _rb_usb_send;
static uint8_t _rb_usb_send_buf[5120] = { 0 };
static TX_SEMAPHORE _sem_usb_send;


extern void SystemClock_Config(void);

static int bsp_rcc_reset()
{
    RCC_ClkInitTypeDef RCC_ClkInitStruct = { 0 };
    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
    if(HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK) {
        Error_Handler();
    }
    return 0;
}

static void _usb_reenumerate()
{
    GPIO_InitTypeDef GPIO_InitStruct;
    __HAL_RCC_GPIOB_CLK_ENABLE();
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_15, GPIO_PIN_RESET);
    GPIO_InitStruct.Pin = GPIO_PIN_15;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_PULLDOWN;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_15, GPIO_PIN_RESET);
    uint64_t start = bsp_ktime();
    while(bsp_ktime() - start < 100000);
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_15, GPIO_PIN_SET);
    while(bsp_ktime() - start < 100000);

}

static void _task_usb_send_hdl(uint32_t args)
{
    UNUSED(args);
    uint8_t buf[1024];
    uint32_t flags;
    while(1) {
        tx_semaphore_get(&_sem_usb_send, TX_WAIT_FOREVER);
        int sz = rb_read(&_rb_usb_send, buf, sizeof(buf));
        if(sz > 0) {
            int ret = CDC_Transmit_HS(buf, sz);
            if(ret != USBD_OK) {
                bsp_printf(" #! usb send failed <%d>\r\n", ret);
            }
            tx_event_flags_get(&_events_communicate, _USB_TX_EVENT, TX_OR_CLEAR, &flags, TX_WAIT_FOREVER);
        }
    }
}

void bsp_usb_send_flag_set()
{
    tx_event_flags_set(&_events_communicate, _USB_TX_EVENT, TX_OR);
}

static void _task_uart1_send_hdl(uint32_t args)
{
    UNUSED(args);
    uint32_t flags;
    static uint8_t buf[2048];
    while(1) {
        tx_semaphore_get(&_sem_uart1_tx, TX_WAIT_FOREVER);
        int sz = rb_read(&_rb_uart1_tx, buf, sizeof(buf));
        if(sz > 0) {
            HAL_UART_Transmit_DMA(&huart1, buf, sz);
            tx_event_flags_get(&_events_communicate, _UART1_TX_EVENT, TX_OR_CLEAR, &flags, TX_WAIT_FOREVER);
        }
    }
}

static int _mutex_usb_send_lock()
{
    return tx_mutex_get(&_mutex_usb_send, TX_WAIT_FOREVER);
}

static int _mutex_usb_send_unlock()
{
    return tx_mutex_put(&_mutex_usb_send);
}

static int _mutex_uart1_lock()
{
    return tx_mutex_get(&_mutex_rb_uart1_tx, TX_WAIT_FOREVER);
}

static int _mutex_uart1_unlock()
{
    return tx_mutex_put(&_mutex_rb_uart1_tx);
}

/* rewrite delay function, because of the threadx,
    using original HAL_Delay, the process will be crashed.
 */
void HAL_Delay(uint32_t ms)
{
    uint64_t start = bsp_ktime();
    while(bsp_ktime() - start < ms * 1000);
}

int bsp_init(void)
{
    HAL_Init();
    bsp_rcc_reset();
    SystemClock_Config();
    MX_GPIO_Init();
    MX_DMA_Init();
    MX_CAN1_Init();
    MX_ADC1_Init();
    MX_TIM1_Init();
    MX_TIM2_Init();
    MX_TIM3_Init();
    MX_TIM4_Init();
    MX_TIM5_Init();
    MX_TIM8_Init();
    MX_TIM14_Init();
    tx_mutex_create(&_mutex_rb_uart1_tx, "mutex_rb_uart1_tx", TX_NO_INHERIT);
    tx_mutex_create(&_mutex_usb_send, "mutex_usb_send", TX_NO_INHERIT);
    tx_semaphore_create(&_sem_uart1_tx, "sem_uart1_tx", 0);
    tx_semaphore_create(&_sem_usb_send, "sem_usb_send", 0);
    rb_init(&_rb_uart1_rx, _rb_uart1_rx_buf, sizeof(_rb_uart1_rx_buf), NULL, NULL);
    rb_init(&_rb_uart1_tx, _rb_uart1_tx_buf, sizeof(_rb_uart1_tx_buf), _mutex_uart1_lock, _mutex_uart1_unlock);
    rb_init(&_rb_usb_recv, _rb_usb_recv_buf, sizeof(_rb_usb_recv_buf), NULL, NULL);
    rb_init(&_rb_usb_send, _rb_usb_send_buf, sizeof(_rb_usb_send_buf), _mutex_usb_send_lock, _mutex_usb_send_unlock);
    tx_event_flags_create(&_events_communicate, "event_uart");
    MX_USART1_UART_Init();
    MX_ADC2_Init();
    HAL_TIM_Base_Start_IT(&htim14);

    _usb_reenumerate();

    MX_USB_DEVICE_Init();

    bsp_printf("\033[H\033[2J");
    bsp_printf("  ___  ____  ____  _____     _______\r\n");
    bsp_printf(" / _ \\|  _ \\|  _ \\|_ _\\ \\   / / ____|\r\n");
    bsp_printf("| | | | | | | |_) || | \\ \\ / /|  _|\r\n");
    bsp_printf("| |_| | |_| |  _ < | |  \\ V / | |___ \r\n");
    bsp_printf(" \\__\\_\\____/|_| \\_\\___|  \\_/  |_____|\r\n");
    bsp_printf(" QDRIVE FIRMWARE, %s, %s\r\n", __DATE__, __TIME__);
    bsp_printf(" Designed by luoqi\r\n");

    tx_thread_create(&_task_uart1_send, "uart1_send", _task_uart1_send_hdl, 0, _task_uart1_send_stack, sizeof(_task_uart1_send_stack), 5, 5, TX_NO_TIME_SLICE, TX_AUTO_START);
    tx_thread_create(&_task_usb_send, "usb_send", _task_usb_send_hdl, 0, _task_usb_send_stack, sizeof(_task_usb_send_stack), 3, 3, TX_NO_TIME_SLICE, TX_AUTO_START);

    HAL_UARTEx_ReceiveToIdle_DMA(&huart1, _uart1_rx_buf, sizeof(_uart1_rx_buf));
    return 0;
}

void bsp_os_startup(void)
{
    _osstartup = true;
}

int bsp_sys_init(void)
{
    MX_ThreadX_Init();
    return 0;
}

int bsp_deinit()
{
    HAL_DeInit();
    return 0;
}

__WEAK void i2c1_txcplt_cb(void)
{
    
}

__WEAK void i2c1_rxcplt_cb(void)
{
    
}

__WEAK void i2c2_txcplt_cb(void)
{
    
}

__WEAK void i2c2_rxcplt_cb(void)
{
    
}

void HAL_I2C_MemRxCpltCallback(I2C_HandleTypeDef *hi2c)
{
    if(hi2c->Instance == I2C1) {
        i2c1_rxcplt_cb();
    } else if(hi2c->Instance == I2C2) {
        i2c2_rxcplt_cb();
    }   
}

void HAL_I2C_MemTxCpltCallback(I2C_HandleTypeDef *hi2c)
{
    if(hi2c->Instance == I2C1) {
        i2c1_txcplt_cb();
    } else if(hi2c->Instance == I2C2) {
        i2c2_txcplt_cb();
    }
}

void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
    if(huart->Instance == USART1) {
        rb_write(&_rb_uart1_rx, _uart1_rx_buf, Size);
        tx_event_flags_set(&_events_communicate, _UART1_RX_EVENT, TX_OR);
        HAL_UARTEx_ReceiveToIdle_DMA(huart, _uart1_rx_buf, sizeof(_uart1_rx_buf));
    }
}

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
    if(huart->Instance == USART1) {
        tx_event_flags_set(&_events_communicate, _UART1_TX_EVENT, TX_OR);
    }
}

void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
    if(__HAL_UART_GET_FLAG(huart, UART_FLAG_ORE) != RESET) {
        __HAL_UART_CLEAR_OREFLAG(huart);
    }
    if(__HAL_UART_GET_FLAG(huart, UART_FLAG_IDLE) != RESET) {
        __HAL_UART_CLEAR_IDLEFLAG(huart);
    }
    if(__HAL_UART_GET_FLAG(huart, UART_FLAG_FE) != RESET) {
        __HAL_UART_CLEAR_FEFLAG(huart);
    }
    if(__HAL_UART_GET_FLAG(huart, UART_FLAG_NE) != RESET) {
        __HAL_UART_CLEAR_NEFLAG(huart);
    }

    if(huart->Instance == USART1) {
        bsp_printf(" #! uart1 error ! <%d>\r\n", huart->ErrorCode);
        HAL_UARTEx_ReceiveToIdle_DMA(huart, _uart1_rx_buf, sizeof(_uart1_rx_buf));
        tx_event_flags_set(&_events_communicate, _UART1_TX_EVENT, TX_OR);
    }
}

int bsp_printf(const char *fmt, ...)
{
    char buf[256] = { 0 };
    va_list args;
    va_start(args, fmt);
    int sz = vsnprintf(buf, sizeof(buf) - 1, fmt, args);
    va_end(args);

    if(sz < 0) {
        const char *err_str = " #! Print parse failed\r\n";
        sz = (int)strlen(err_str);
        memcpy(buf, err_str, sz);
    } else if(sz >= sizeof(buf)) {
        sz = sizeof(buf) - 1;
    }

    int ret = 0;
    if(_osstartup) {
        ret = rb_write(&_rb_uart1_tx, (uint8_t *)buf, sz);
        tx_semaphore_put(&_sem_uart1_tx);
    } else {
        ret = HAL_UART_Transmit(&huart1, (uint8_t *)buf, sz, 100);
    }
    return ret;
}

int bsp_uart1_recv(uint8_t *data, uint32_t len, uint32_t timeout)
{
    uint32_t flags;
    tx_event_flags_get(&_events_communicate, _UART1_RX_EVENT, TX_OR_CLEAR, &flags, timeout);
    return rb_read(&_rb_uart1_rx, data, len);
}

int bsp_uart1_received(void)
{
    return rb_used(&_rb_uart1_rx);
}

int bsp_usb_send(const uint8_t *data, uint16_t len)
{
    int txsz = rb_write(&_rb_usb_send, data, len);
    tx_semaphore_put(&_sem_usb_send);
    return txsz;
}

int bsp_usb_recv_rb_write(uint8_t *data, uint16_t len)
{
    int sz = rb_write(&_rb_usb_recv, data, len);
    tx_event_flags_set(&_events_communicate, _USB_RX_EVENT, TX_OR);
    return sz;
}

int bsp_usb_recv(uint8_t *data, uint16_t len, uint32_t timeout)
{
    uint32_t flags;
    tx_event_flags_get(&_events_communicate, _USB_RX_EVENT, TX_OR_CLEAR, &flags, timeout);
    return rb_read(&_rb_usb_recv, data, len);
}

void bsp_led_set(BspLedState state)
{
    switch(state) {
    case BSP_LED_ON:
        HAL_GPIO_WritePin(BLINK_GPIO_Port, BLINK_Pin, GPIO_PIN_RESET);
        break;
    case BSP_LED_OFF:
        HAL_GPIO_WritePin(BLINK_GPIO_Port, BLINK_Pin, GPIO_PIN_SET);
        break;
    default:
        break;
    }
}

/* called by main.c  function void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) */
static volatile uint32_t systime_over_cnt = 0;
void tim14_period_elapsed_callback(void)
{
    systime_over_cnt++;
}

qtime_t bsp_ktime(void)
{
    uint32_t counter = __HAL_TIM_GET_COUNTER(&htim14);
    qtime_t time = counter + (qtime_t)systime_over_cnt * 0xffff;

    return time;
}

void bsp_mdelay(uint32_t ms)
{
    HAL_Delay(ms);
}

void bsp_udelay(uint32_t us)
{
    qtime_t start = bsp_ktime();
    while(bsp_ktime() - start < us);
}

void bsp_reboot(void)
{
    __disable_irq();
    HAL_NVIC_SystemReset();
}

uint32_t bsp_strlen(const char *s)
{
    uint32_t len = 0;
    while(*s++ != '\0') {
        len++;
    }
    return len;
}

void *bsp_memcpy(void *dest, const void *src, uint32_t len)
{
    char *d;
    const char *s;
    if(((uint32_t)dest > ((uint32_t)src + len)) || (dest < src)) {
        d = dest;
        s = src;
        while(len--) {
            *d++ = *s++;
        }
    } else {
        d = (char *)((uint32_t)dest + len - 1);
        s = (char *)((uint32_t)src + len - 1);
        while(len--) {
            *d-- = *s--;
        }
    }
    return dest;
}
